package nl.sweet.testsweet.command;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedList;

import nl.sweet.testsweet.TestSweet;
import nl.sweet.testsweet.TestSweetListener;
import nl.sweet.testsweet.TestSweetResult;
import nl.sweet.testsweet.TestSweetSuite;
import nl.sweet.testsweet.TestSweetTestCase;
import nl.sweet.testsweet.TestSweetXMLHandler;

/**
 * The entry point for the command prompt version of TestSweet.
 * @author wessels
 */
public class Main
{
	/**
	 * The entry point for the command line version of the application.
	 * @param args Arguments parsed to the application.
	 */
	public static void main(String[] args)
	{
		if (args.length == 3) {
			try {
				String testSuiteClass = args[0];
				String outputFormat = args[1].toLowerCase();
				String outputFileLocation = args[2];
				if (!(outputFormat.equals("xml") || outputFormat.equals("html"))) {
					System.out.println("The output format should be either xml or html.");
					return;
				} else if (!new File(outputFileLocation).isAbsolute() || new File(outputFileLocation).isDirectory()) {
					System.out.println("The given file is not correct, it is not absolute or is a directory.");
					return;
				}
				TestSweetSuite testSuite = (TestSweetSuite) Class.forName(testSuiteClass).newInstance();
				new Main(testSuite, outputFormat, outputFileLocation);
			} catch (IllegalAccessError ex) {
				ex.printStackTrace();
			}
			catch (InstantiationException e)
			{
				e.printStackTrace();
			}
			catch (IllegalAccessException e)
			{
				e.printStackTrace();
			}
			catch (ClassNotFoundException e)
			{
				System.out.println("The given test suite class does not implement " + TestSweetSuite.class.toString());
			}
		} else {
			System.out.println("java -jar testsweet-command.jar [testsuite-class] [output-format (xml or html)] [save file location]");
			System.out.println("Example: java -jar testsweet-command.jar nl.testsweet.sample.test.TestSweetSuiteExample html /root/testoutput.html");
		}
	}
	
	/**
	 * Constructor.
	 * @param testSuite The test suite to perform.
	 */
	public Main(TestSweetSuite testSuite, String fileType, String fileLocation) {
		new TestSweet(testSuite.getTestClasses(), new CommandTestListener(System.out, fileType, fileLocation));
	}
	
	private void saveToFile(String fileType, String fileLocation, CommandTestListener _app) {
		try
		{
			TestSweetXMLHandler xmlHandler = new TestSweetXMLHandler(
					_app.getTestSweetResults(), _app.getTotalTime());
			if (fileType.equals("xml")) {
				FileOutputStream out = new FileOutputStream(fileLocation);;
				xmlHandler.saveXMLToOutputStream(out);
				out.close();
			} else if (fileType.equals("html")) {
				FileWriter writer = new FileWriter(fileLocation);
				xmlHandler.saveHTMLToWriter(writer);
				writer.close();
			}
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	/**
	 * The test listener for the command prompt version of test sweet.
	 * @author wessels
	 */
	private class CommandTestListener implements TestSweetListener {
		/** The stream to output the information to. */
		private PrintStream outputStream;
		
		/** The list with the results. */
		private LinkedList<TestSweetResult> _testSweetResults;
		
		/** The total time taken. */
		private double _totalTimeTaken;
		
		private String fileType;
		
		private String fileLocation;
		
		/**
		 * Constructor.
		 * @param printStream The output stream for realtime information.
		 */
		public CommandTestListener(PrintStream printStream, String fileType, String fileLocation) {
			outputStream = printStream;
			this.fileType = fileType;
			this.fileLocation = fileLocation;
			_testSweetResults = new LinkedList<TestSweetResult>();
		}

		/**
		 * @see nl.sweet.testsweet.TestSweetListener#addTestSuiteResult(nl.sweet.testsweet.TestSweetResult)
		 */
		public void addTestSuiteResult(TestSweetResult testSuiteResult)
		{
			_testSweetResults.add(testSuiteResult);
			outputStream.println("Test '" + testSuiteResult.getTestCaseName() + "' is done");
		}

		/**
		 * @see nl.sweet.testsweet.TestSweetListener#setAmountOfTests(int)
		 */
		public void setAmountOfTests(int totalTests)
		{
			outputStream.println("Total amount of tests: " + totalTests);
		}

		/**
		 * @see nl.sweet.testsweet.TestSweetListener#setCurrentTest(int, java.lang.Class)
		 */
		public void setCurrentTest(int currentTest, Class< ? extends TestSweetTestCase> testClass)
		{
			outputStream.println("Test " + currentTest + " is running.");
		}

		/**
		 * @see nl.sweet.testsweet.TestSweetListener#setTotalTime(double)
		 */
		public void setTotalTime(double totalTime)
		{
			_totalTimeTaken = totalTime;
			outputStream.println("Total time of testing: " + totalTime + "ms");
			outputStream.println("Writing results to file: " + fileLocation + ".");
			saveToFile(fileType, fileLocation, this);
			outputStream.println("Done.");
		}
		
		/**
		 * Get the total time taken.
		 * @return The total time taken.
		 */
		public double getTotalTime()
		{
			return _totalTimeTaken;
		}
		
		/**
		 * Get the results.
		 * @return The results.
		 */
		public LinkedList<TestSweetResult> getTestSweetResults()
		{
			return _testSweetResults;
		}
	}
}
